﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Hydra.Core;

namespace Hydra.Fake
{
    public class Payload : IPayload
    {
        private static IParasiteLogger log = Hospital.GetLogger();

        [StructLayout(LayoutKind.Sequential)]
        private class DetourEntity
        {
            public string lpLibFileName;
            public string lpProcName;
            public IntPtr pDetour;
            public IntPtr pPointer;
        }

        [DllImport("core-x64")]
        private static extern int AceDetour(
            [MarshalAs(UnmanagedType.LPArray)]DetourEntity[] entities,
            int length);

        public int Apply()
        {
            var entries = new[]
                {
                    new DetourEntity
                        {
                            lpLibFileName = "comdlg32",
                            lpProcName = "PrintDlgExW",
                            pDetour = Marshal.GetFunctionPointerForDelegate(new PrintDlgEx(PrintDlgExCallback)),
                            pPointer = IntPtr.Zero,
                        },
                    new DetourEntity
                        {
                            lpLibFileName = "shell32",
                            lpProcName = "ShellAboutW",
                            pDetour = Marshal.GetFunctionPointerForDelegate(new ShellAbout(ShellAboutCallback)),
                            pPointer = IntPtr.Zero,
                        },
                };
            var ret = AceDetour(entries, entries.Length);

            if (ret == 0)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            _pPrintDlgEx = (PrintDlgEx)Marshal.GetDelegateForFunctionPointer(entries[0].pPointer, typeof(PrintDlgEx));
            _pShellAbout = (ShellAbout)Marshal.GetDelegateForFunctionPointer(entries[1].pPointer, typeof(ShellAbout));

            return ret;
        }

        public int Undo()
        {
            throw new NotImplementedException();
        }



        private delegate IntPtr PrintDlgEx(IntPtr lppd);
        private delegate int ShellAbout(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)]string szApp, [MarshalAs(UnmanagedType.LPWStr)]string szOtherStuff, IntPtr hIcon);

        private PrintDlgEx _pPrintDlgEx;
        private ShellAbout _pShellAbout;

        private IntPtr PrintDlgExCallback(IntPtr lppd)
        {
            log.Info("Call PrintDlgEx()");
            return _pPrintDlgEx(lppd);
        }
        private int ShellAboutCallback(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)]string szApp, [MarshalAs(UnmanagedType.LPWStr)]string szOtherStuff, IntPtr hIcon)
        {
            log.Info("ShellAbout({0}, {1}, {2}, {3})", hWnd, szApp, szOtherStuff, hIcon);
            return _pShellAbout(hWnd, szApp, szOtherStuff, hIcon);
        }
    }
}
